//The MIT License (MIT)
//
//Copyright (c) 2020 lihp1603
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in
//all copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//THE SOFTWARE.

package proc

import (
	"errors"
	"io/ioutil"
	"strconv"
	"strings"
)

func ReadLoadAvg() (*LoadAvg, error) {
	return readLoadAvg("/proc/loadavg")
}

func readLoadAvg(path string) (*LoadAvg, error) {

	b, err := ioutil.ReadFile(path)

	if err != nil {
		return nil, err
	}

	content := strings.TrimSpace(string(b))
	fields := strings.Fields(content)

	if len(fields) < 5 {
		return nil, errors.New("Cannot parse loadavg: " + content)
	}

	process := strings.Split(fields[3], "/")

	if len(process) != 2 {
		return nil, errors.New("Cannot parse loadavg: " + content)
	}

	loadavg := LoadAvg{}

	if loadavg.Last1Min, err = strconv.ParseFloat(fields[0], 64); err != nil {
		return nil, err
	}

	if loadavg.Last5Min, err = strconv.ParseFloat(fields[1], 64); err != nil {
		return nil, err
	}

	if loadavg.Last15Min, err = strconv.ParseFloat(fields[2], 64); err != nil {
		return nil, err
	}

	if loadavg.ProcessRunning, err = strconv.ParseUint(process[0], 10, 64); err != nil {
		return nil, err
	}

	if loadavg.ProcessTotal, err = strconv.ParseUint(process[1], 10, 64); err != nil {
		return nil, err
	}

	if loadavg.LastPID, err = strconv.ParseUint(fields[4], 10, 64); err != nil {
		return nil, err
	}

	return &loadavg, nil
}

type LoadAvg struct {
	Last1Min       float64 `json:"last1min"`
	Last5Min       float64 `json:"last5min"`
	Last15Min      float64 `json:"last15min"`
	ProcessRunning uint64  `json:"process_running"`
	ProcessTotal   uint64  `json:"process_total"`
	LastPID        uint64  `json:"last_pid"`
}

func (la *LoadAvg) GetLast1Min() float64 {
	return la.Last1Min
}

func (la *LoadAvg) GetLast5Min() float64 {
	return la.Last5Min
}

func (la *LoadAvg) GetLast15Min() float64 {
	return la.Last15Min
}
